package ggaviator

import (
	"sync"
	"sync/atomic"
	"wzgames/internal/codec/sfs"
	"wzgames/internal/constant"
	"wzgames/internal/response"
	"wzgames/internal/services/games"
	"wzgames/pkg/logger"
)

// 播报通知分组

type Notifier struct {
	mu       sync.RWMutex
	airCraft *AirCraft
	msgChan  chan interface{}
	stopCh   chan struct{}
	mapGt    map[uint64]*games.GameTable // 玩家登录游戏注册
	cl       int32
}

func newNotifier(chanSize int64, airCraft *AirCraft) *Notifier {
	nt := &Notifier{
		airCraft: airCraft,
		msgChan:  make(chan interface{}, chanSize),
		stopCh:   make(chan struct{}, 1),
		mapGt:    make(map[uint64]*games.GameTable),
	}
	go nt.Run()
	return nt
}

func (nt *Notifier) Notify(msg interface{}) {
	if atomic.LoadInt32(&nt.cl) == 1 {
		return
	}
	nt.msgChan <- msg
}

func (nt *Notifier) NotifyMulti(roundId int64, currMultiplier, maxMulti float64, currTime int64, crash bool) {
	if atomic.LoadInt32(&nt.cl) == 1 {
		return
	}
	nt.msgChan <- CurrMultiplier{
		RoundId:    roundId,
		Multi:      currMultiplier,
		MaxMulti:   maxMulti,
		TimeElapse: currTime,
		Crash:      crash,
	}
}

func (nt *Notifier) Run() {
	defer logger.RecoverPanic()
	for {
		select {
		case m := <-nt.msgChan:
			switch v := m.(type) {
			case *sfs.RawPacket: // 小飞机投注等播报
				nt.broadcastSfsObject(v)
				response.ReleaseMsgO(v)
			case CurrMultiplier: // 小飞机赔率播报
				nt.broadcastMultiplier(v.RoundId, v.Multi, v.MaxMulti, v.TimeElapse, v.Crash)
			default:
				nt.broadcast(m)
			}
		case <-nt.stopCh:
			return
		}
	}
}

func (nt *Notifier) broadcastMultiplier(roundId int64, currMultiplier, maxMulti float64, currTime int64, crash bool) {
	xw := sfs.XWriter{}
	defer xw.Reset()
	var paramN uint16 = 3
	if crash {
		paramN = 5
	}
	xw.WriteUShort(uint16(2))
	xw.WriteStringS(sfs.CmdKey, constant.KeyCurrentMultiplier)
	xw.WriteSfsObjectPre(sfs.ParamId, paramN)
	xw.WriteDoubleS(constant.KeyCurrentPayout, currMultiplier)
	xw.WriteIntS(sfs.KeyCode, 200)
	xw.WriteLongS(constant.KeyCurrentGameTime, currTime)
	if crash {
		xw.WriteDoubleS(constant.KeyCrashMultiplier, currMultiplier)
		xw.WriteBoolS(constant.KeyCrash, crash)
	}

	nt.mu.RLock()
	defer nt.mu.RUnlock()

	for _, gt := range nt.mapGt {
		if gt != nil {
			m := response.AcquireMsgO13()
			xw.WriteTo(m)
			gt.Sess.Send(m)
			if gt.Marker != nil {
				gt.Marker.(*AviatorMarker).CheckAutoCashOutPoint(gt, nt.airCraft, roundId, currMultiplier, maxMulti)
			}
		}
	}
}

func (nt *Notifier) broadcastSfsObject(v *sfs.RawPacket) {
	nt.mu.RLock()
	defer nt.mu.RUnlock()

	for _, gt := range nt.mapGt {
		if gt != nil {
			m := response.AcquireMsgO()
			m.Id = v.Id
			m.ControlId = v.ControlId
			m.Write(v.Content)
			gt.Sess.Send(m)
		}
	}
}

func (nt *Notifier) broadcast(msg interface{}) {
	nt.mu.RLock()
	defer nt.mu.RUnlock()

	for _, gt := range nt.mapGt {
		if gt != nil {
			gt.Sess.Send(msg)
		}
	}
}

func (nt *Notifier) Register(tb *games.GameTable) {
	nt.mu.Lock()
	nt.mapGt[tb.Player.ID()] = tb
	nt.mu.Unlock()
}

func (nt *Notifier) Unregister(playerId uint64) {
	nt.mu.Lock()
	delete(nt.mapGt, playerId)
	nt.mu.Unlock()
}

func (nt *Notifier) Close() {
	atomic.StoreInt32(&nt.cl, 1)
	//close(nt.msgChan)
	nt.stopCh <- struct{}{}
	close(nt.stopCh)
}
